/**
 WhereIsMyMail Copyright (c) 2012 Artem Kuroptev

 This file is part of WhereIsMyMail. WhereIsMyMail is free software: you can redistribute it and/or modify it
 under the terms of the GNU General Public License as published by the Free Software Foundation,
 either version 3 of the License, or (at your option) any later version.

 WhereIsMyMail is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 See the GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with WhereIsMyMail. If not, see <http://www.gnu.org/licenses/>.
 */

package com.ucware.wimm.imaps;

import com.ucware.wimm.AbstractUp;

import javax.mail.*;
import javax.mail.search.AndTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.SearchTerm;
import java.io.IOException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Properties;
import java.util.TimeZone;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * $Id: Fetch.java 23 2014-11-25 21:00:34Z kuroptev@gmail.com $
 * @created 01.12.2012
 * @author Artem Kuroptev
 */
public class Fetch extends AbstractUp
{
    private static Logger log = Logger.getLogger(Fetch.class.getName());
    protected static void log(Object s) {log.info(s.toString());}
    protected static void log(Throwable s) {log.log(Level.SEVERE, s.getLocalizedMessage(), s);}

    public static final String BEFORE = "com.ucware.wimm.imaps.Up.before";
    public static final String AFTER = "com.ucware.wimm.imaps.Up.after";

    public static final long MAX_TZ_DIFF_H = 26;
    public static final long MAX_TZ_DIFF_MS = MAX_TZ_DIFF_H*60*60*1000;
    protected static final String MSG_TIME_DIFF_WARNING = "Some messages may not be fetched due to time difference between server time and local time. Max difference is {0} hours.";
    public static final long MILLIS_IN_DAY = 1000*60*60*24;

    // 'Z' means that this date-time is in UTC timezone.
    // So time zone must be set explictly
    static {ATOM_DATETIME_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));}

    public static void main(String[] args) {
        try {
            setupLogManager();
            log("$Id: Fetch.java 23 2014-11-25 21:00:34Z kuroptev@gmail.com $");
            if(args.length < 1) {
                log("usage: java com.ucware.wimm.imaps.Fetch <imaps://user:password@host:port/path> [after-atom [before-atom]] ");
                return;
            }

            final Properties properties = new Properties();
            if(args.length > 1) { properties.setProperty(AFTER, args[1]); }
            if(args.length > 2) { properties.setProperty(BEFORE, args[2]); }

            fetch(args[0], properties, getDatePropertyOrNull(properties, AFTER), getDatePropertyOrNull(properties, BEFORE));
        }
        catch (Exception e){
            log(e);
        }
    }

    public static void fetch(final String url, final Properties properties, final Date after, final Date before) throws MessagingException, ParseException, IOException
    {
        // Search terms
        final ArrayList<SearchTerm> searchTerms = new ArrayList<SearchTerm>();
        if(after != null) {
            searchTerms.add(new ReceivedDateTerm(ReceivedDateTerm.GE, after));
            log("ReceivedDateTerm.GE (after) added: " + after); // NB! This will print time in default time zone, not in UTC.

            if(Math.abs(after.getTime() - System.currentTimeMillis()) < MAX_TZ_DIFF_MS) {
                log.warning(MessageFormat.format(MSG_TIME_DIFF_WARNING, MAX_TZ_DIFF_H));
            }
        }

        if(before != null) {
            searchTerms.add(new ReceivedDateTerm(ReceivedDateTerm.LT, before));
            log("ReceivedDateTerm.LT (before) added: " + before);  // NB! This will print time in default time zone, not in UTC.
            if(Math.abs(before.getTime() - System.currentTimeMillis()) < MAX_TZ_DIFF_MS) {
                log.warning(MessageFormat.format(MSG_TIME_DIFF_WARNING, MAX_TZ_DIFF_H));
            }
        }

        // properties.put("mail.debug", "true");

        // Connect
        final Session session = Session.getInstance(properties, null);
        final URLName urlName = new URLName(url);
        final Folder folder = session.getFolder(urlName);
        final Store store = folder.getStore();

        log("Folder open: " + folder.isOpen());
        log("Opening the folder.. ");
        folder.open(Folder.READ_ONLY);
        
        try {
            log("folder.getMessageCount(): " + folder.getMessageCount());

            final Message[] messages; // Don't know if messages are in some order
            if(searchTerms.size() > 0 ){
                final AndTerm term = new AndTerm(searchTerms.toArray(new SearchTerm[searchTerms.size()]));
                log("Calling folder.search(searchTerms): " + term);
                messages = folder.search(term);
            }
            else {
                log("No search terms. Calling folder.getMessages().. ");
                messages = folder.getMessages();
            }

            log("Light-weight Message objects retrieved: " + messages.length);

            // Retriving and saving
            exportMessages(messages);
        }
        finally {
            folder.close(false);
            store.close();
        }
    }
}
